from log import getLogger
logger=getLogger('sleep')

import stackless
import time

from actor import Actor

class SleepManager(Actor):

    def __init__(self,*args,**kwargs):
        Actor.__init__(self,*args,**kwargs)

        self.sleepingTasklets=[]

    def sleep(self,secondsToWait):
        channel = stackless.channel()
        endTime = time.time() + secondsToWait
        self.sleepingTasklets.append((endTime, channel))
        self.sleepingTasklets.sort()
        # Block until we get sent an awakening notification.
        channel.receive()

    def ManageSleepingTasklets(self):
        if len(self.sleepingTasklets):
            endTime = self.sleepingTasklets[0][0]
            if endTime <= time.time():
                channel = self.sleepingTasklets[0][1]
                del self.sleepingTasklets[0]
                # We have to send something, but it doesn't matter what as it is not used.
                logger.debug('waking')

                channel.send(None)
            elif stackless.getruncount() == 1:
                # We are the only tasklet running, the rest are blocked on channels sleeping.
                # We can call time.sleep until the first awakens to avoid a busy wait.
                delay = endTime - time.time()
                #print "wait delay", delay
                time.sleep(max(delay,0))

    def defaultEventHandler(self):

        while True:

            if self.channel.balance: # somebody gives this a message
                logger.debug('stuck')
                event=self.channel.receive()

                if event.subject=='quit':
                    break

            self.ManageSleepingTasklets()

            stackless.schedule()

